package org.summer.lawyer.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.summer.common.core.exception.ServiceException;
import org.summer.common.core.utils.MapstructUtils;
import org.summer.common.json.utils.JsonUtils;
import org.summer.common.mybatis.core.page.PageQuery;
import org.summer.common.mybatis.core.page.TableDataInfo;
import org.summer.common.satoken.utils.LoginHelper;
import org.summer.lawyer.constant.SystemConstants;
import org.summer.lawyer.domain.BrokerageUser;
import org.summer.lawyer.domain.bo.brokeragerecord.BrokerageRecordBo;
import org.summer.lawyer.domain.bo.brokerageuser.BrokerageUserBo;
import org.summer.lawyer.domain.bo.brokerageuser.CommissionBo;
import org.summer.lawyer.domain.vo.brokerageconfig.BrokerageConfigVo;
import org.summer.lawyer.domain.vo.brokeragerecord.BrokerageRecordVo;
import org.summer.lawyer.domain.vo.brokerageuser.BrokerageUserVo;
import org.summer.lawyer.domain.vo.paytransfer.PayTransferVo;
import org.summer.lawyer.domain.vo.spuorder.SpuOrderVo;
import org.summer.lawyer.domain.vo.spuorderassign.SpuOrderAssignVo;
import org.summer.lawyer.domain.vo.userwallet.UserWalletVo;
import org.summer.lawyer.domain.vo.wxuser.WxUserVo;
import org.summer.lawyer.mapper.BrokerageUserMapper;
import org.summer.lawyer.service.*;
import org.summer.lawyer.util.IdWorkerUtil;
import org.summer.lawyer.util.ParamsUtil;

import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 分销员Service业务层处理
 *
 * @author summer
 * @date 2024-06-20
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class BrokerageUserServiceImpl extends ServiceImpl<BrokerageUserMapper, BrokerageUser> implements IBrokerageUserService {


    private final IUserWalletService userWalletService;
   // private final IUserWalletLogService userWalletLogService;
    private final IBrokerageRecordService brokerageRecordService;
    private final IBrokerageConfigService brokerageConfigService;
    private final IWxUserService wxUserService;
    private final ISpuOrderAssignService spuOrderAssignService;

    /**
     * 查询分销员
     *
     * @param brokerageUserId 主键
     * @return 分销员
     */
    @Override
    public BrokerageUserVo selectBrokerageUserVoById(Long brokerageUserId) {
        return baseMapper.selectVoById(brokerageUserId);
    }

    @Override
    public BrokerageUserVo selectBrokerageUserVoByWxUserId(Long wxUserId) {
        LambdaQueryWrapper<BrokerageUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(BrokerageUser::getWxUserId, wxUserId);
        BrokerageUserVo brokerageUser = baseMapper.selectVoOne(lqw, false);
        if (brokerageUser == null) {
            throw new ServiceException("请联系管理员创建分销员信息");
        }
        //查询我的钱包信息
        UserWalletVo userWalletVo = userWalletService.selectUserWalletVoByUserId(wxUserId);
        brokerageUser.setWalletIncome(userWalletVo.getWalletIncome());
        brokerageUser.setWalletExpense(userWalletVo.getWalletExpense());
        brokerageUser.setBalanceFee(userWalletVo.getBalanceFee());
        brokerageUser.setFrozenAmount(userWalletVo.getFrozenAmount());
        //30天新增人数
        Date date = DateUtil.date();
        // Date endDate = DateUtil.beginOfDay(date);
        Date beginDate = DateUtil.offsetDay(DateUtil.beginOfDay(date), -30);
        Integer userCount = selectUserCount(brokerageUser.getBrokerageUserId(), beginDate, date);
        brokerageUser.setNewUserCount(userCount);
        // 今日收入
        Long income = brokerageRecordService.selectTotalAmountByDay(wxUserId, date);
        brokerageUser.setTodayAmount(income);
        //生成邀请二维码
        String qrContent = StrUtil.format("{}?brokerageCode={}", SystemConstants.QR_IMAGE_URL, brokerageUser.getBrokerageCode());
        BufferedImage image = QrCodeUtil.generate(qrContent, 300, 300);
        brokerageUser.setQrImage(ImgUtil.toBase64DataUri(image, ImgUtil.IMAGE_TYPE_PNG));
        return brokerageUser;
    }

    @Override
    public BrokerageUserVo selectNullBrokerageUserVoByWxUserId(Long wxUserId) {
        LambdaQueryWrapper<BrokerageUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(BrokerageUser::getWxUserId, wxUserId);
        return baseMapper.selectVoOne(lqw, false);
    }

    @Override
    public BrokerageUserVo selectBrokerageUserVoByBrokerageCode(String brokerageCode) {
        LambdaQueryWrapper<BrokerageUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(BrokerageUser::getBrokerageCode, brokerageCode);
        return baseMapper.selectVoOne(lqw, false);
    }

    /**
     * 分页查询分销员列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 分销员分页列表
     */
    @Override
    public TableDataInfo<BrokerageUserVo> selectPageList(BrokerageUserBo bo, PageQuery pageQuery) {
        QueryWrapper<BrokerageUser> lqw = buildQueryWrapper(bo);
        Page<BrokerageUserVo> result = baseMapper.selectPageList(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的分销员列表
     *
     * @param bo 查询条件
     * @return 分销员列表
     */
    @Override
    public List<BrokerageUserVo> selectBrokerageUserVoList(BrokerageUserBo bo) {
        LambdaQueryWrapper<BrokerageUser> lqw = Wrappers.lambdaQuery();
        return baseMapper.selectVoList(lqw);
    }

    private QueryWrapper<BrokerageUser> buildQueryWrapper(BrokerageUserBo bo) {
        Map<String, Object> params = ParamsUtil.getParams(bo.getParams());
        QueryWrapper<BrokerageUser> lqw = Wrappers.query();
        lqw.eq(bo.getWxUserId() != null, "bu.wx_user_id", bo.getWxUserId());
        lqw.like(StrUtil.isNotBlank(bo.getNickname()), "wu.nickname", bo.getNickname());
        lqw.eq(StrUtil.isNotBlank(bo.getBrokerageCode()), "bu.brokerage_code", bo.getBrokerageCode());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), "bu.status", bo.getStatus());
        lqw.eq(bo.getUserCount() != null, "bu.user_count", bo.getUserCount());
        lqw.eq(bo.getOrderCount() != null, "bu.order_count", bo.getOrderCount());
        lqw.eq(bo.getOrderAmount() != null, "bu.order_amount", bo.getOrderAmount());
        lqw.eq(bo.getWithdrawAmount() != null, "bu.withdraw_amount", bo.getWithdrawAmount());
        lqw.eq(bo.getWithdrawCount() != null, "bu.withdraw_count", bo.getWithdrawCount());
        lqw.eq(bo.getBindUserId() != null, "bu.bind_user_id", bo.getBindUserId());
        lqw.like(StrUtil.isNotBlank(bo.getBindUserName()), "bu.bind_user_name", bo.getBindUserName());
        lqw.between(params.get("beginTime") != null && params.get("endTime") != null, "bu.brokerage_time", params.get("beginTime"), params.get("endTime"));
        lqw.orderByDesc("bu.brokerage_time");
        return lqw;
    }

    /**
     * 新增分销员
     *
     * @param bo 分销员
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(BrokerageUserBo bo) {
        BrokerageUser add = MapstructUtils.convert(bo, BrokerageUser.class);
        validEntityBeforeSave(add);
        add.setStatus(SystemConstants.ACTIVE);
        add.setCreateTime(DateUtil.date());
        add.setUpdateTime(DateUtil.date());
        add.setBrokerageTime(DateUtil.date());
        if (StrUtil.isEmpty(add.getBrokerageCode())) {
            add.setBrokerageCode(IdWorkerUtil.nextIdStr());
        }
        if (LoginHelper.getLoginUser() != null) {
            add.setCreateBy(LoginHelper.getLoginUser().getUserId());
            add.setUpdateBy(LoginHelper.getLoginUser().getUserId());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setBrokerageUserId(add.getBrokerageUserId());
        }
        return flag;
    }

    /**
     * 修改分销员
     *
     * @param bo 分销员
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(BrokerageUserBo bo) {
        BrokerageUser update = MapstructUtils.convert(bo, BrokerageUser.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(BrokerageUser entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除分销员信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public void changeBrokerageUserStatus(BrokerageUserBo bo) {
        LambdaUpdateWrapper<BrokerageUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BrokerageUser::getBrokerageUserId, bo.getBrokerageUserId())
                .set(BrokerageUser::getStatus, bo.getStatus());
        baseMapper.update(updateWrapper);
    }

    @Override
    public Integer selectUserCount(Long bindUserId, Date beginTime, Date endTime) {
        LambdaQueryWrapper<BrokerageUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(BrokerageUser::getBindUserId, bindUserId);
        lqw.between(BrokerageUser::getBindUserTime, beginTime, endTime);
        return baseMapper.selectCount(lqw).intValue();
    }

    /**
     * 佣金结算
     */
    @Lock4j(keys = "{#bo.brokerageRecordId}", acquireTimeout = 1000, expire = 10000)
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public void commissionSettlement(CommissionBo bo) {
        log.info("[commissionSettlement][用户({})]参数：{}", bo.getWxUserId(), JsonUtils.toJsonString(bo));
        BrokerageRecordVo brokerageRecordVo = brokerageRecordService.selectBrokerageRecordVoById(bo.getBrokerageRecordId());
        if (brokerageRecordVo == null) {
            throw new ServiceException("佣金记录未找到");
        }
        //待结算状态
        if("0".equals(brokerageRecordVo.getStatus())) {
            //更新用户钱包收入
            userWalletService.walletIncome(brokerageRecordVo);
            //更新佣金记录
            BrokerageRecordBo brokerageRecordBo = new BrokerageRecordBo();
            BeanUtils.copyProperties(brokerageRecordVo, brokerageRecordBo);
            brokerageRecordBo.setStatus("1");
            brokerageRecordService.updateByBo(brokerageRecordBo);
            log.info("[commissionSettlement][用户({})]更新佣金记录成功", bo.getWxUserId());
            //更新推广员统计
            BrokerageUserVo brokerageUser = selectBrokerageUserVoByWxUserId(brokerageRecordVo.getWxUserId());
            BrokerageUserBo brokerageUserBo = new BrokerageUserBo();
            BeanUtils.copyProperties(brokerageUser, brokerageUserBo);
            //推广订单数量
            Integer orderCount = brokerageUser.getOrderCount();
            orderCount += 1;
            brokerageUserBo.setOrderCount(orderCount);
            //推广订单金额
            Long orderAmount = brokerageUser.getOrderAmount();
            orderAmount += brokerageRecordVo.getAmount();
            brokerageUserBo.setOrderAmount(orderAmount);
            //已提现金额
            Long withdrawAmount = brokerageUser.getWithdrawAmount();
            withdrawAmount += brokerageRecordVo.getAmount();
            brokerageUserBo.setWithdrawAmount(withdrawAmount);
            //已提现次数
            Integer withdrawCount = brokerageUser.getWithdrawCount();
            withdrawCount += 1;
            brokerageUserBo.setWithdrawCount(withdrawCount);
            this.updateByBo(brokerageUserBo);
            log.info("[commissionSettlement][用户({})]更新推广员信息成功: {}", bo.getWxUserId(), JsonUtils.toJsonString(brokerageUserBo));
        }
    }

    @Override
    public void bindBrokerageUser(BrokerageUserBo bo) {
        //查询是否已被绑定
        BrokerageUserVo selfBrokerageUserVo = selectNullBrokerageUserVoByWxUserId(bo.getWxUserId());
        if (selfBrokerageUserVo != null && selfBrokerageUserVo.getBindUserId() != null) {
            log.info("{}已被{}绑定，不能绑定其他分销用户", selfBrokerageUserVo.getNickname(), selfBrokerageUserVo.getBindUserName());
            return;
        }
        //获取用户信息
        WxUserVo wxUserVo = wxUserService.selectWxUserVoById(bo.getWxUserId());
        if (wxUserVo == null) {
            log.info("用户{}还未注册，请注册后再绑定", bo.getWxUserId());
            return;
        }
        BrokerageUserVo brokerageUserVo = selectBrokerageUserVoByBrokerageCode(bo.getBrokerageCode());
        if (brokerageUserVo != null) {
            bo.setBindUserId(brokerageUserVo.getBrokerageUserId());
            bo.setBindUserName(brokerageUserVo.getNickname());
            bo.setBindUserTime(DateUtil.date());
            //更新推广人数
            int userCount = brokerageUserVo.getUserCount() != null ? brokerageUserVo.getUserCount() : 0;
            BrokerageUser brokerageUser = new BrokerageUser();
            brokerageUser.setBrokerageUserId(brokerageUserVo.getBrokerageUserId());
            brokerageUser.setUserCount(userCount + 1);
            LambdaUpdateWrapper<BrokerageUser> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(BrokerageUser::getBrokerageUserId, brokerageUserVo.getBrokerageUserId());
            baseMapper.update(brokerageUser, updateWrapper);

        }
        bo.setBrokerageTime(DateUtil.date());
        bo.setUserCount(0);
        bo.setOrderAmount(0L);
        bo.setWithdrawAmount(0L);
        bo.setWithdrawCount(0);
        bo.setNickname(wxUserVo.getNickname());
        bo.setAvatar(wxUserVo.getAvatar());
        this.insertByBo(bo);
    }

    // @Lock4j()
    @DSTransactional(rollbackFor = Exception.class)
    @Override
    public void createBrokerageFee(SpuOrderVo vo) {

        BrokerageConfigVo brokerageConfigVo = brokerageConfigService.selectOneBrokerageConfigVo();
        //查询派单信息
        SpuOrderAssignVo orderAssignVo = spuOrderAssignService.selectSpuOrderAssignVoBySpuOrderId(vo.getOrderId());
        if (orderAssignVo != null && orderAssignVo.getWxUserId() != null) {
            //计算律师订单分成
            BrokerageUserVo brokerageUserVo = selectNullBrokerageUserVoByWxUserId(orderAssignVo.getWxUserId());
            if(brokerageUserVo != null && SystemConstants.ACTIVE.equals(brokerageUserVo.getStatus())) {
                Double orderBrokerageAmount = orderAssignVo.getAmount() * brokerageConfigVo.getOrderPercent() * 0.01;
                BrokerageRecordBo orderBrokerageBo = new BrokerageRecordBo();
                orderBrokerageBo.setWxUserId(orderAssignVo.getWxUserId());
                orderBrokerageBo.setBizId(String.valueOf(vo.getOrderId()));
                orderBrokerageBo.setBizType("1");
                orderBrokerageBo.setBizPicture(orderAssignVo.getSpuImage());
                orderBrokerageBo.setTitle(orderAssignVo.getSpuName());
                orderBrokerageBo.setTotalAmount(orderAssignVo.getAmount());
                orderBrokerageBo.setFirstPercent(brokerageConfigVo.getOrderPercent());
                orderBrokerageBo.setAmount(orderBrokerageAmount.longValue());
                orderBrokerageBo.setStatus("0");
                orderBrokerageBo.setFrozenDay(brokerageConfigVo.getBrokerageFrozenDay());
                orderBrokerageBo.setCreateTime(DateUtil.date());
                orderBrokerageBo.setUnfreezeTime(DateUtil.date());
                if(orderBrokerageBo.getFrozenDay() > 0){
                    orderBrokerageBo.setUnfreezeTime(DateUtil.offsetDay(orderBrokerageBo.getCreateTime(), orderBrokerageBo.getFrozenDay()));
                }
                orderBrokerageBo.setSourceUserId(brokerageUserVo.getBrokerageUserId());
                orderBrokerageBo.setSourceUserName(brokerageUserVo.getNickname());
                orderBrokerageBo.setSourceUserLevel(1);
                brokerageRecordService.insertByBo(orderBrokerageBo);
                log.info("[createBrokerageFee][用户({})][订单编号({})]创建订单分成：{}", orderAssignVo.getWxUserId(), orderAssignVo.getOrderNumber(), JsonUtils.toJsonString(orderBrokerageBo));
            }
        }
        //计算佣金
        if (SystemConstants.ACTIVE.equals(brokerageConfigVo.getEnableBrokerage())) {
            BrokerageUserVo brokerageUserVo = selectNullBrokerageUserVoByWxUserId(vo.getUserId());
            if (brokerageUserVo != null && SystemConstants.ACTIVE.equals(brokerageUserVo.getStatus())) {
                //上级推广员信息
                BrokerageUserVo rootBrokerageUser = selectBrokerageUserVoById(brokerageUserVo.getBindUserId());
                //计算佣金
                Double rootBrokerageAmount = vo.getAmount() * brokerageConfigVo.getFirstPercent() * 0.01;
                BrokerageRecordBo brokerageRecordBo = new BrokerageRecordBo();
                brokerageRecordBo.setWxUserId(rootBrokerageUser.getWxUserId());
                brokerageRecordBo.setBizId(String.valueOf(vo.getOrderId()));
                brokerageRecordBo.setBizType("2");
                brokerageRecordBo.setBizPicture(vo.getSpuImage());
                brokerageRecordBo.setTitle(vo.getSpuImage());
                brokerageRecordBo.setTotalAmount(vo.getAmount());
                brokerageRecordBo.setFirstPercent(brokerageConfigVo.getFirstPercent());
                brokerageRecordBo.setAmount(rootBrokerageAmount.longValue());
                brokerageRecordBo.setStatus("0");
                brokerageRecordBo.setFrozenDay(brokerageConfigVo.getBrokerageFrozenDay());
                brokerageRecordBo.setCreateTime(DateUtil.date());
                brokerageRecordBo.setUnfreezeTime(DateUtil.date());
                if(brokerageRecordBo.getFrozenDay() > 0){
                    brokerageRecordBo.setUnfreezeTime(DateUtil.offsetDay(brokerageRecordBo.getCreateTime(), brokerageRecordBo.getFrozenDay()));
                }
                brokerageRecordBo.setSourceUserId(brokerageUserVo.getBrokerageUserId());
                brokerageRecordBo.setSourceUserName(brokerageUserVo.getNickname());
                brokerageRecordBo.setSourceUserLevel(1);
                brokerageRecordService.insertByBo(brokerageRecordBo);
                log.info("[createBrokerageFee][用户({})][订单编号({})]创建佣金分成：{}", orderAssignVo.getWxUserId(), orderAssignVo.getOrderNumber(), JsonUtils.toJsonString(brokerageRecordBo));
            }
        }

    }

    @Override
    public void updateBrokerageWithdraw(PayTransferVo vo) {
        BrokerageUserVo brokerageUserVo = selectBrokerageUserVoByWxUserId(vo.getUserId());
        if (brokerageUserVo != null) {
            BrokerageUser brokerageUser = new BrokerageUser();
            brokerageUser.setBrokerageUserId(brokerageUserVo.getBrokerageUserId());
            Long withdrawAmount = brokerageUserVo.getWithdrawAmount() + vo.getAmount();
            Integer withdrawCount = brokerageUserVo.getWithdrawCount() + 1;
            brokerageUser.setWithdrawAmount(withdrawAmount);
            brokerageUser.setWithdrawCount(withdrawCount);
            brokerageUser.setUpdateTime(DateUtil.date());
            LambdaUpdateWrapper<BrokerageUser> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.eq(BrokerageUser::getBrokerageUserId, brokerageUserVo.getBrokerageUserId());
            baseMapper.update(brokerageUser, updateWrapper);
        } else {
            log.info("[{}]未找到分销员信息。", vo.getUserId());
        }
    }
}
